package org.peoples {
	
	import com.qualityattributes.errors.UnsupportedOperationError;
	
	import flash.events.EventDispatcher;
	import flash.events.NetStatusEvent;
	
	import mx.collections.ArrayCollection;
	import mx.controls.Alert;
	
	import org.peoples.rooms.IRoomProxy;
	import org.peoples.rooms.RoomHandler;
	import org.peoples.rooms.RoomPool;
	import org.peoples.rooms.RoomPoolEvent;
	import org.peoples.rooms.RoomProperties;
	import org.peoples.rooms.RoomProxy;
	import org.peoples.users.IUserProxy;
	import org.peoples.users.User;
	import org.peoples.users.UserHandler;
	import org.peoples.users.UserPool;
	import org.peoples.users.UserProxy;
	
	[Bindable]
	public final class Peoples extends EventDispatcher {
		
		private var _rooms:RoomPool;
		private var _users:UserPool;
		
		private var _joinedRooms:ArrayCollection;
		private var _roomCollection:ArrayCollection;
		private var _userCollection:ArrayCollection;
		
		private var _roomProxy:IRoomProxy;
		private var _userProxy:IUserProxy;
		
		private var _loginUser:User;
		
		private static var instance:Peoples;
		private static var init:Boolean = false;
		
		private const uri:String = "rtmp://localhost/peoples";
		
		public function Peoples():void {
			if (!init)
				throw new UnsupportedOperationError("Peoples must be instantiated using Peoples.getInstance()");
			
			this._joinedRooms = new ArrayCollection();
			this.joinedRooms.addItem("Lobby");
			this._roomCollection = new ArrayCollection();
			this._userCollection = new ArrayCollection();
			
			this._rooms = RoomPool.getInstance();
			this._rooms.addEventListener(RoomPoolEvent.ROOM_ADDED, onAddRoom, false, 0, true);
			this._rooms.addEventListener(RoomPoolEvent.ROOM_REMOVED, onRemoveRoom, false, 0, true);
			
			this._users = UserPool.getInstance();
			
			this._roomProxy = new RoomProxy(uri, new RoomHandler());
			this._roomProxy.connection.addEventListener(NetStatusEvent.NET_STATUS, onRoomProxyConnect, false, 0, true);
			
			this._userProxy = new UserProxy(uri, new UserHandler());
			this._userProxy.connection.addEventListener(NetStatusEvent.NET_STATUS, onUserProxyConnect, false, 0, true);
			
		}
		
		public function initialize(user:User):void {
			this._loginUser = user;
			
			this._userProxy.connect();
		}
		
		private function containsRoom(room:RoomProperties):Boolean {
			var len:int = _roomCollection.length;
			for (var i:int = 0; i < len; i++) {
				var t_room:RoomProperties = _roomCollection[i];
				if (room.equals(t_room))
					return true;
			}
			
			return false;
		}
		
		private function roomIndex(room:RoomProperties):int {
			var len:int = _roomCollection.length;
			for (var i:int = 0; i < len; i++) {
				var t_room:RoomProperties = _roomCollection[i];
				if (room.equals(t_room))
					return i;
			}
			
			return -1;
		}
		
		private function onAddRoom(evt:RoomPoolEvent):void {
			if (!containsRoom(evt.room))
				_roomCollection.addItem(evt.room);
		}
		
		private function onRemoveRoom(evt:RoomPoolEvent):void {
			var index:int = roomIndex(evt.room);
			if (index != -1)
				_roomCollection.removeItemAt(index);
		}
		
		private function checkConnectionErrors(evt:NetStatusEvent):void {
			if (evt.info.code == "NetConnection.Connect.Failed") {
				Alert.show("There was an error while connecting to the server.", "Connection Error");
			} else if (evt.info.code == "NetConnection.Connect.AppShutdown", "Connection Error") {
				Alert.show("The application server is shutting down.", "Connection Error");
			} else if (evt.info.code == "NetConnection.Connect.Rejected", "Connection Error") {
				Alert.show("Your connection to the server has been refused.", "Connection Error");
			} else if (evt.info.code == "NetConnection.Connect.InvalidApp", "Connection Error") {
				Alert.show("The supplied application name is invalid.", "Connection Error");
			}
		}
		
		private function onRoomProxyConnect(evt:NetStatusEvent):void {
			if (evt.info.code == "NetConnection.Connect.Success") {
				_roomProxy.getRooms();
			} else {
				checkConnectionErrors(evt);
			}
		}
		
		private function onUserProxyConnect(evt:NetStatusEvent):void {
			if (evt.info.code == "NetConnection.Connect.Success") {
				_userProxy.userJoin(_loginUser.firstName, _loginUser.lastName, new Date());
				_roomProxy.connect();
			} else {
				checkConnectionErrors(evt);
			}
		}
		
		public static function getInstance():Peoples {
			init = true;
			
			if (instance == null)
				instance = new Peoples();
				
			return instance;
		}
		
		public function get joinedRooms():ArrayCollection {
			return this._joinedRooms;
		}
		
		public function get rooms():ArrayCollection {
			return this._roomCollection;
		}
		
		public function get roomProxy():IRoomProxy {
			return this._roomProxy;
		}
		
		public function get userProxy():IUserProxy {
			return this._userProxy;
		}
		
	}
	
}